home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume91
/
utilitys
/
ed3_1_1
/
part02
/
edgr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-07
|
17KB
|
811 lines
/*
These are functions of the 3D editor that handle graphics.
10-16-91 finish_move now checks to see if there is room in the undo buf
09-26-91 add redraw_newface() (to aid proper screen refreshing)
09-06-91 add void draw_point_sub()
adapted to use coord instead of short
09-04-91 fix to del_face()
08-28-91 fix black-non-deleted-point glitch
08-24-91 add glue feature
08-23-91 add distance_tool(), draw_distance_tool(), draw_distance()
08-15-91 add circle_point
08-14-91 (replaced handle_button with handle_gadget)
08-13-91 added ability to run on the workbench screen
06-25-90 Polygons added to allow dualization of polyhedra.
*/
#include "sysgr.h"
#include <math.h> /* for draw_rot() */
extern int gadget_spacing, baseline;
Point3D move_from; /* base xyz for group moves */
void draw_3d()
{
}
/* draw/erase the points currently being dragged */
void toggle_dragged_points()
{
index i, p;
EdPoint temp;
movement.x = gx - move_from.x;
movement.y = gy - move_from.y;
movement.z = gz - move_from.z;
m_setmode(dm_comp); /* then update it on the screen */
for (i = 0; i < selected; ++i)
{
p = select_p[i];
temp.x = point[p].x + movement.x;
temp.y = point[p].y + movement.y;
temp.z = point[p].z + movement.z;
convert_point_sub(&temp);
draw_point_sub(&temp); /* draw/erase */
}
m_setmode(dm_norm);
}
void add_segment(p)
uindex p;
{
index seg, f;
int draw_flag = 0;
Face *fp;
if (p >= points) return; /* must be valid */
if (p == last_point) return; /* don't connect a face to itself */
if (flags.shape == M_FACE)
{
fp = face + faces;
switch(new_seg)
{
case 2:
/* see if a face already exists there */
f = points_are_a_face(fp->p[0], fp->p[1], p);
if (f >= 0)
{
screen_say("Those three points are already connected by a face");
break;
}
/* notice there is no break here */
case 1:
if (p == fp->p[0]) break; /* no lines! */
fp->p[new_seg++] = p; /* add this point to the face array */
draw_flag = 1;
}
if (new_seg == 3)
{
tri_up_point(fp->p[0]); /* erase triangle */
tri_up_point(fp->p[1]); /* erase triangle */
/* we could just increment faces, but we call add_faces so that */
/* the action is logged */
begin_operation();
add_face(fp->p[0], fp->p[1], p, colors.newface, 0); /* not silent */
end_operation();
m_setpen1(colors.face);
draw_face(faces-1);
new_seg = 0;
mode = M_FACE;
draw_bars();
return;
}
}
else if (flags.shape == M_POLY)
{
/* polygon completed by clicking the first point */
if (p == first_point)
{
if (new_seg < 3) return; /* no lines! */
begin_operation();
add_poly(new_seg, colors.newface, temp_poly, 0);
end_operation();
for (seg = 0; seg < new_seg; seg++)
tri_up_point(temp_poly[seg]); /* erase triangle */
m_setpen1(colors.face);
draw_poly(polys-1); /* draw the newly created polygon */
new_seg = 0;
mode = M_POLY;
draw_bars();
return;
}
else /* add this point to the new polygon */
{
/* add this point to the new polygon */
temp_poly[new_seg++] = p;
draw_flag = 1;
}
}
if (draw_flag)
{
m_setpen1(colors.box);
convert_to_xy(point[last_point].x, point[last_point].y, point[last_point].z);
m_move(px, py);
convert_to_xy(point[p].x, point[p].y, point[p].z);
m_draw(px, py);
tri_up_point(p); /* erase triangle */
last_point = p;
}
}
void del_face(f, silent)
index f;
int silent;
{
index i1;
index fa[3], po[3], p[3];
for (i1 = 0; i1 < 3; i1++) /* remember the points */
p[i1] = face[f].p[i1];
for (i1 = 0; i1 < 3; i1++) /* remember the surrounding faces */
{
fa[i1] = face_next_to_edge(p[i1], p[(i1+1)%3], f);
po[i1] = poly_next_to_edge(p[i1], p[(i1+1)%3], -1);
}
m_setpen1(colors.erase);
draw_face(f);
delete_face(f, silent);
m_setpen1(colors.face);
for (i1 = 0; i1 < 3; i1++) /* redraw the surrounding faces */
{
if (fa[i1] == faces) fa[i1] = f;
if (fa[i1] >= 0)
draw_face(fa[i1]);
if (po[i1] >= 0)
draw_poly(po[i1]);
}
for (i1 = 0; i1 < 3; i1++) draw_point(p[i1], colors.point);
}
void del_poly(q, silent)
index q;
int silent;
{
index verts, i1;
index fa[MAX_EDGES], po[MAX_EDGES], p[MAX_EDGES];
verts = poly[q].verts;
for (i1 = 0; i1 < verts; i1++) /* remember the points */
p[i1] = poly[q].p[i1];
for (i1 = 0; i1 < verts; i1++) /* remember the surrounding faces */
{
fa[i1] = face_next_to_edge(p[i1], p[(i1+1)%verts], -1);
po[i1] = poly_next_to_edge(p[i1], p[(i1+1)%verts], q);
}
m_setpen1(colors.erase);
draw_poly(q);
delete_poly(q, silent); /* low-level delete */
m_setpen1(colors.face);
for (i1 = 0; i1 < verts; i1++) /* redraw the surrounding faces */
{
if (po[i1] == polys) po[i1] = q;
if (fa[i1] >= 0)
draw_face(fa[i1]);
if (po[i1] >= 0)
draw_poly(po[i1]);
}
for (i1 = 0; i1 < verts; i1++) draw_point(p[i1], colors.point);
}
void kill_segment(p) /* delete the face/poly that touches this point */
uindex p;
{
index f, q, seg;
if (p >= points) return; /* must be valid */
if (flags.shape == M_FACE)
{
/* only select a valid point: the new point must be a vertex
of the face being killed */
switch (new_seg)
{
case 1:
f = face_next_to_edge(face[faces].p[0], p, -1);
if (f >= 0)
{
face[faces].p[new_seg++] = p; /* add this point to the face array */
tri_down_point(p); /* draw triangle */
}
break;
case 2:
f = points_are_a_face(face[faces].p[0], face[faces].p[1], p);
if (f < 0) return; /* must be valid */
tri_down_point(face[faces].p[0]); /* erase triangles */
tri_down_point(face[faces].p[1]);
begin_operation();
del_face(f, 0);
end_operation();
new_seg = 0;
mode = M_DEFA;
draw_bars();
#if 0
refresh_all();
#endif
return;
break;
}
}
else
if (flags.shape == M_POLY)
{
/* polygon completed by clicking the first point */
if (p == first_point)
{
if (new_seg < 3) return; /* need at least 3 points */
q = points_are_on_a_poly(temp_poly, new_seg);
if (new_seg == poly[q].verts)
{
/* found it */
for (seg = 0; seg < new_seg; seg++)
tri_down_point(temp_poly[seg]); /* erase triangles */
del_poly(q, 0);
new_seg = 0;
mode = M_DEPO;
draw_bars();
#if 0
refresh_all();
#endif
return;
}
}
else /* add this point to the killed polygon list */
{
temp_poly[new_seg++] = p; /* add this point to the new polygon */
q = points_are_on_a_poly(temp_poly, new_seg);
if (q < 0) /* not a polygon */
{
new_seg--;
return;
}
else /* we have a valid point */
{
tri_down_point(p); /* draw triangle */
}
}
}
}
void distance_tool(buttons, current_p)
char buttons;
index current_p;
{
long dist0, dist1;
int which_end;
pixel dx, dy;
if (buttons == 1) return; /* ignore second button */
/* find which end of the dtool we're closer to */
convert_to_xy(dtool_end[0].x, dtool_end[0].y, dtool_end[0].z);
dx = mx - px;
dy = my - py;
dist0 = isqrt(dx*dx + dy*dy);
convert_to_xy(dtool_end[1].x, dtool_end[1].y, dtool_end[1].z);
dx = mx - px;
dy = my - py;
dist1 = isqrt(dx*dx + dy*dy);
which_end = (dist1 < dist0);
#if 0
draw_distance_tool(); /* erase old location */
#endif
/* if there was no point selected, we cannot allow a double-click */
if ((buttons & MF_DOUBLE) && current_p < 0) buttons = 0;
switch (buttons)
{
case 0: /* first button clicked once */
draw_distance_tool(); /* erase old location */
flags.drag_dtool = 1;
flags.which_end = which_end;
dtool_end[which_end].attached = 0;
draw_distance_tool(); /* draw at new location */
break;
case 2: /* first button double-clicked */
draw_distance_tool(); /* erase old location */
flags.drag_dtool = 0;
dtool_end[which_end].attached = 1;
dtool_end[which_end].p = current_p;
draw_distance_tool(); /* draw at new location */
break;
}
}
void finish_move()
{
index i1;
/* Make sure that this event won't overflow the undo buffer */
if (!enough_room(0, 0, 0, 0, 0, 0, selected, 0))
{
/* this operation will overflow the undo buffer! */
if (!tell_user_overflow())
{
flags.moving_points = 0;
flags.copy_made = 0;
return;
}
}
begin_operation();
for (i1 = 0; i1 < selected; ++i1)
{
draw_point(select_p[i1], colors.erase);
/* actually apply the movement specified */
move_point_rel(select_p[i1], movement.x, movement.y, movement.z);
/* and redraw the point in its new location */
draw_point(select_p[i1], colors.point);
}
end_operation();
if (faces+polys < REFRESH_LEVEL) refresh_all(); /* kinda arbitrary */
flags.moving_points = 0;
flags.copy_made = 0;
}
void start_moving_point(buttons, p)
int buttons;
uindex p;
{
index i;
if (p >= points) return; /* must be valid */
if (!selected || buttons & MF_SHIFTED) /* select one or multiple points */
{
if (buttons & MF_DOUBLE) /* double click */
{
select_connected(p);
}
else select_point(p);
}
else /* start to move all selected points */
{
flags.moving_points = 1;
m_setmode(dm_comp); /* and start xoring */
for (i = 0; i < selected; i++)
draw_point(select_p[i], -1);
m_setmode(dm_norm);
move_from.x = gx; /* remember where the mouse went down */
move_from.y = gy;
move_from.z = gz;
movement = vector0; /* start right here */
}
}
void draw_points(clear)
char clear;
{
uindex p;
if (clear)
{
m_setpen1(colors.erase);
m_rectfill(edit_minx, edit_miny, sxmax, symax);
}
for (p = 0; p < points; p++)
{
draw_point(p, colors.point);
if (pselected(p)) box_point(p);
}
}
void draw_point(p, pcol)
register uindex p;
int pcol;
{
if (pcol >= 0) m_setpen1(pcol); /* -1 means use current color */
if (p > points) return; /* must be valid, must allow p == points */
draw_point_sub(point + p);
}
void draw_point_sub(p)
EdPoint *p;
{
pixel px, py;
if (p->code & PF_CLIP) return; /* must be on-screen */
px = p->px;
py = p->py;
m_move(px, py-1);
m_draw(px, py+1);
m_move(px-1, py);
m_draw(px+1, py);
}
void draw_hair()
{
m_setmode(dm_comp);
convert_to_xy(gx, gy, gz);
m_move(edit_minx, py);
m_draw(sxmax-1, py);
m_move(px, edit_miny+1);
m_draw(px, symax-1);
m_setmode(dm_norm);
}
void draw_distance_tool()
{
index i, p;
coord x[2], y[2], z[2];
double dx, dy, dz;
m_setmode(dm_comp);
for (i = 0; i < 2; i++)
{
if (dtool_end[i].attached)
{
p = dtool_end[i].p;
dtool_end[i].x = x[i] = point[p].x;
dtool_end[i].y = y[i] = point[p].y;
dtool_end[i].z = z[i] = point[p].z;
}
else
{
x[i] = dtool_end[i].x;
y[i] = dtool_end[i].y;
z[i] = dtool_end[i].z;
}
convert_to_xy(x[i], y[i], z[i]);
if (!i)
m_move(px, py);
else
m_draw(px, py);
}
m_setmode(dm_norm);
dx = x[1] - x[0];
dy = y[1] - y[0];
dz = z[1] - z[0];
distance = sqrt(dx*dx + dy*dy + dz*dz);
draw_distance();
}
void redraw_newface() /* redraw a partially-completed face or poly */
{
uindex i1;
/* there must be at least one line segment (2 points) already defined */
if (new_seg < 2) return;
if (flags.shape == M_FACE)
{
for (i1 = 0; i1 < new_seg-1; i1++)
clip_draw(face[faces].p[i1], face[faces].p[i1+1]);
}
else
{
for (i1 = 0; i1 < new_seg-1; i1++)
clip_draw(temp_poly[i1], temp_poly[i1+1]);
}
}
void draw_faces(clear) /* kinda obvious */
char clear;
{
uindex i;
if (clear)
{
m_setpen1(colors.erase);
m_rectfill(edit_minx, edit_miny, sxmax, symax);
}
m_setpen1(colors.face);
for (i = 0; i < faces; i++) draw_face(i);
for (i = 0; i < polys; i++) draw_poly(i); /* do the polygons too */
}
void draw_face_color(f, col)
uindex f;
int col;
{
m_setpen1(col);
draw_face(f);
}
void draw_face(f) /* kinda obvious */
uindex f;
{
uindex p0, p1, p2;
p0 = face[f].p[0];
p1 = face[f].p[1];
p2 = face[f].p[2];
clip_draw(p0, p1);
clip_draw(p1, p2);
clip_draw(p2, p0);
}
void draw_poly_color(q, col) /* kinda obvious */
uindex q;
short col;
{
m_setpen1(col);
draw_poly(q);
}
void draw_poly(p) /* kinda obvious */
uindex p;
{
register uindex i, n, next;
n = poly[p].verts;
for (i = 0; i < n; i++)
{
next = (i+1==n ? 0 : i+1);
clip_draw(poly[p].p[i], poly[p].p[next]);
}
}
/* draw the little angle-measure thingy */
void draw_rot()
{
pixel x = (pixel)(cos(rot_angle)*50.);
pixel y = (pixel)(sin(rot_angle)*50.);
m_setmode(dm_comp);
convert_to_xy(axis.x, axis.y, axis.z);
m_move(px+50, py);
m_draw(px, py);
m_draw(px+x, py-y);
m_setmode(dm_norm);
}
/* Draw the bars which show you what mode and color you're using */
void draw_bars()
{
int y;
/* clear bar region */
m_setpen1(colors.erase);
m_rectfill(GADX-6, edit_miny, GADX, symax);
/* editing mode bar */
m_setpen1(colors.point);
y = edit_miny + mode * gadget_spacing;
m_rectfill(GADX-6, y, GADX, y + gadget_spacing);
/* display mode bar */
m_setpen1(colors.face);
y = edit_miny + (dmode+GID_XY-1) * gadget_spacing;
m_rectfill(GADX-6, y, GADX, y + gadget_spacing);
/* color bar */
m_setpen1(colors.point);
y = edit_miny + (colors.newface+GID_color1-2) * gadget_spacing;
m_rectfill(GADX-6, y, GADX, y + gadget_spacing);
}
void show_counts()
{
m_setpen1(colors.titlea);
m_setpen2(colors.titleb);
m_move(GADX+16, edit_miny+baseline);
sprintf(title, "%3d points %3d faces %3d polys ", points, faces, polys);
m_text(title, 31);
}
void draw_coords(erase)
int erase;
{
if (erase)
{
m_setpen1(colors.erase);
m_setpen2(colors.erase);
}
else
{
m_setpen1(colors.titlea);
m_setpen2(colors.titleb);
}
m_move(GADX+280, edit_miny+baseline);
#if INTEGER
sprintf(title, "X%4d Y%4d Z%4d ", gx, gy, gz);
m_text(title, 23L);
#else
sprintf(title, "X%- 10.4lf Y%- 10.4lf Z%- 10.4lf", gx, gy, gz);
m_text(title, 35L);
#endif
}
void draw_distance()
{
m_setpen1(colors.titlea);
m_setpen2(colors.titleb);
m_move(GADX+524, edit_miny+baseline);
sprintf(title, "%4.3f ", distance);
m_text(title, 8L);
}
void box_point(p) /* draw a box around a point */
register uindex p;
{
pixel px, py;
if (p >= points) return; /* must be valid */
if (off_screen(p)) return; /* must be on-screen */
m_setmode(dm_comp);
px = point[p].px;
py = point[p].py;
m_move(px-2, py-2);
m_draw(px-2, py+2);
m_draw(px+2, py+2);
m_draw(px+2, py-2);
m_draw(px-2, py-2);
m_setmode(dm_norm);
}
void tri_up_point(p) /* draw a triangle around a point */
register uindex p;
{
pixel px, py;
m_setmode(dm_comp);
if (p >= points) return; /* must be valid */
if (off_screen(p)) return; /* must be on-screen */
px = point[p].px;
py = point[p].py;
m_move(px , py-4);
m_draw(px-6, py+2);
m_draw(px+6, py+2);
m_draw(px+1, py-3);
m_move(px , py-3);
m_draw(px-4, py+1);
m_move(px+1, py-2);
m_draw(px+4, py+1);
m_setmode(dm_norm);
}
void tri_down_point(p) /* draw a triangle around a point */
register uindex p;
{
pixel px, py;
m_setmode(dm_comp);
if (p >= points) return; /* must be valid */
if (off_screen(p)) return; /* must be on-screen */
px = point[p].px;
py = point[p].py;
m_move(px , py+4);
m_draw(px-6, py-2);
m_draw(px+6, py-2);
m_draw(px+1, py+3);
m_move(px , py+3);
m_draw(px-4, py-1);
m_move(px+1, py+2);
m_draw(px+4, py-1);
m_setmode(dm_norm);
}
/*
Draw a line between two points, clipping into the editing area
if necessary. Everything is done with pixel coordinates.
*/
void clip_draw(p0, p1)
register uindex p0, p1;
{
pixel x0, y0, x1, y1;
register short c0, c1;
register pixel dx, dy; /* clipping codes and distances */
x0 = point[p0].px;
y0 = point[p0].py;
x1 = point[p1].px;
y1 = point[p1].py;
/* pre-generated clipping codes */
c0 = (point[p0].code & PF_CLIP);
c1 = (point[p1].code & PF_CLIP);
#if 0
if (flags.debug) printf(" (%d,%d) to (%d, %d), c0 %d, c1 %d.\n",
x0, y0, x1, y1, c0, c1);
#endif
while (c0 | c1)
{
if (c0&c1) return; /* entirely off-screen: don't draw it */
dx = x1 - x0;
dy = y1 - y0;
if (c0)
{
if (c0 & 8) { y0 += dy*(edit_minx-x0)/dx; x0 = edit_minx; } else
if (c0 & 4) { y0 += dy*(sxmax-x0)/dx; x0 = sxmax; } else
if (c0 & 2) { x0 += dx*(edit_miny-y0)/dy; y0 = edit_miny; } else
if (c0 & 1) { x0 += dx*(symax-y0)/dy; y0 = symax; }
c0 = (x0<edit_minx)<<3 | (x0>sxmax)<<2 | (y0<edit_miny)<<1 | (y0>symax);
}
else
{
if (c1 & 8) { y1 += dy*(edit_minx-x1)/dx; x1 = edit_minx; } else
if (c1 & 4) { y1 += dy*(sxmax-x1)/dx; x1 = sxmax; } else
if (c1 & 2) { x1 += dx*(edit_miny-y1)/dy; y1 = edit_miny; } else
if (c1 & 1) { x1 += dx*(symax-y1)/dy; y1 = symax; }
c1 = (x1<edit_minx)<<3 | (x1>sxmax)<<2 | (y1<edit_miny)<<1 | (y1>symax);
}
}
m_move(x0, y0);
m_draw(x1, y1);
}
void screen_say(str) /* print a string on the screen's title bar */
char *str;
{
char string[80];
strncpy(title, str, 80);
sprintf(string, "%-70s", str);
m_setpen1(colors.titlea);
m_setpen2(colors.titleb);
m_move(GADX+1, edit_miny+baseline);
m_text(string, 70);
}